package com.hliushi.hotel.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hliushi.hotel.entity.Hotel;
import com.hliushi.hotel.entity.HotelDoc;
import com.hliushi.hotel.mapper.HotelMapper;
import com.hliushi.hotel.service.IHotelService;
import com.hliushi.hotel.web.vo.PageResult;
import com.hliushi.hotel.web.vo.RequestVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author llhuang10
 * @date 2021/9/10 22:00
 */
@Slf4j
@Profile("test")      // 指定test环境变量时, 表示使用 mysql 数据源, 不使用es作为检索或者es数据源不存在
@Service
public class DBHotelServiceImpl extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {

    public static final String INDEX_NAME = "hotel";

    /**
     * list查询
     *
     * @param params 请求参数
     * @return PageResult
     */
    @Override
    public PageResult search(RequestVO params) {
        // all字段信息对应了三个字段, brand, name, business
        // 需要拼接动态sql
        int curPage = params.getPage();

        /**
         * bug点, 使用mp分页插件的时候, 这个分页不需要手动去算
         */
        // int curPage = (params.getPage() - 1) * params.getSize();
        int size = params.getSize();
        String key = params.getKey();


        Page<Hotel> result;
        if (StringUtils.isBlank(key)) {
            result = this.page(new Page<>(curPage, size), new QueryWrapper<>());
        } else {
            result = this.page(new Page<>(curPage, size),
                    Wrappers.<Hotel>lambdaQuery()
                            .like(StringUtils.isNotBlank(key), Hotel::getBrand, key)
                            .or()
                            .like(StringUtils.isNotBlank(key), Hotel::getName, key)
                            .or()
                            .like(StringUtils.isNotBlank(key), Hotel::getBusiness, key));
        }

        return this.parseMpPage2PageResult(result);
    }

    /**
     * parseMpPage2PageResult
     *
     * @param result Mp中的PageResult
     * @return PageResult
     */
    private PageResult parseMpPage2PageResult(Page<Hotel> result) {
        PageResult pageResult = new PageResult();

        log.info("============== MpPage result : {}", result.getTotal());
        pageResult.setTotal(result.getTotal());

        List<HotelDoc> collect = result.getRecords().stream()
                .map(HotelDoc::new)
                .collect(Collectors.toList());

        pageResult.setHotels(collect);
        return pageResult;
    }


    /**
     * 有条件过滤的查询
     *
     * @param params 请求参数
     * @param filter 是否过滤
     * @return PageResult
     */
    @Override
    public PageResult search(RequestVO params, Boolean filter) {
        if (!filter) {
            return search(params);
        }

        int curPage = params.getPage();
        int size = params.getSize();
        String key = params.getKey();

        Page<Hotel> result = null;
        if (StringUtils.isBlank(key)) {
            result = super.page(new Page<>(curPage, size), Wrappers.<Hotel>lambdaQuery()
                    .eq(StringUtils.isNotBlank(params.getCity()), Hotel::getCity, params.getCity())
                    .eq(StringUtils.isNotBlank(params.getStarName()), Hotel::getStarName, params.getStarName())
                    .eq(StringUtils.isNotBlank(params.getBrand()), Hotel::getBrand, params.getBrand())
                    .gt(Objects.nonNull(params.getMinPrice()), Hotel::getPrice, params.getMinPrice())
                    .lt(Objects.nonNull(params.getMaxPrice()), Hotel::getPrice, params.getMaxPrice())
                    .orderByAsc("price".equals(params.getSortBy()), Hotel::getPrice)
                    .orderByDesc("score".equals(params.getSortBy()), Hotel::getScore)
            );
        } else {
            result = this.page(new Page<>(curPage, size),
                    Wrappers.<Hotel>lambdaQuery()
                            .and(qw -> qw.like(StringUtils.isNotBlank(key), Hotel::getBrand, key)
                                    .or()
                                    .like(StringUtils.isNotBlank(key), Hotel::getName, key)
                                    .or()
                                    .like(StringUtils.isNotBlank(key), Hotel::getBusiness, key))
                            .eq(StringUtils.isNotBlank(params.getCity()), Hotel::getCity, params.getCity())
                            .eq(StringUtils.isNotBlank(params.getStarName()), Hotel::getStarName, params.getStarName())
                            .eq(StringUtils.isNotBlank(params.getBrand()), Hotel::getBrand, params.getBrand())
                            .gt(Objects.nonNull(params.getMinPrice()), Hotel::getPrice, params.getMinPrice())
                            .lt(Objects.nonNull(params.getMaxPrice()), Hotel::getPrice, params.getMaxPrice())
                            .orderByAsc("price".equals(params.getSortBy()), Hotel::getPrice)
                            .orderByDesc("score".equals(params.getSortBy()), Hotel::getScore)
            );
        }
        // todo 广告算分控制  mysql ??? 哈哈 我怎么解决??
        // todo 距离排序 构建我附近位置的酒店, 并升序排序 ???
        return this.parseMpPage2PageResult(result);
    }

    @Override
    public Map<String, List<String>> filters(RequestVO params) {
        // todo   es对filter做了和search一样的查询条件, 这里先简单点, 先不实现这块逻辑
        //  这里硬编码定义结果顺序

        Map<String, List<String>> result = new LinkedHashMap<>();

        List<String> cityList = this.list(Wrappers.<Hotel>lambdaQuery()
                .groupBy(Hotel::getCity)
                .select(Hotel::getCity))
                .stream().map(Hotel::getCity)
                .collect(Collectors.toList());
        result.put("city", cityList);

        List<String> starNameList = this.list(Wrappers.<Hotel>lambdaQuery()
                .groupBy(Hotel::getStarName)
                .select(Hotel::getStarName))
                .stream().map(Hotel::getStarName)
                .collect(Collectors.toList());
        result.put("starName", starNameList);

        List<String> brandList = this.list(Wrappers.<Hotel>lambdaQuery()
                .groupBy(Hotel::getBrand)
                .select(Hotel::getBrand))
                .stream().map(Hotel::getBrand)
                .collect(Collectors.toList());
        result.put("brand", brandList);

        return result;
    }

    @Override
    public List<String> getSuggestion(String prefix) {
        List<String> suggestionList = new ArrayList<>();
        suggestionList.add("无");
        return suggestionList;

    }

    @Override
    public void insertById(Long id) {
        log.info("=======  DBHotelServiceImpl 实现类无需进行插入或修改操作  ");
    }

    @Override
    public void deleteById(Long id) {
        log.info("=======  DBHotelServiceImpl 实现类无需进行删除操作  ");
    }
}
